package net.aiion.weave.impl.ui.binder;

import net.aiion.weave.spi.cards.Card;
import net.aiion.weave.spi.cards.CardContext;
import net.aiion.weave.spi.conversions.ConverterService;
import net.aiion.weave.spi.injection.annotations.Inject;
import net.aiion.weave.spi.naming.annotations.Named;
import net.aiion.weave.spi.ui.Component;
import net.aiion.weave.spi.ui.annotations.Binds;

public class BinderTemplateSampleDeletMePlease implements Card
{
    public BinderTemplateSampleDeletMePlease() {
    }

    @Override
    public void processCard(CardContext aCardContext) {
        // TODO soll in Card nicht eher gleich in einen PaintBrush gerendert werden??? Dafür ist die Karte doch da?!
        // TODO ggf. PaintBrush dann als Rückgabe für die renderCard-Methode definieren
        // TODO Braucht es wirklich den expressionresolver dann noch im CardContext? Benötigen wir überhaupt dann noch
        // den CardContext?
        // Wenn nicht, kann die Methode nicht gleich die @Paints-Methode für die entsprechende Komponente darstellen?
        // Wann müsste dann aber das XML geparst werden und wie?

        // StartElement: <ui:panel>
        ComponentModel panel = new ComponentModel("ui", "panel");

        // StartElement: <ui:label for="literal:foo">
        ComponentModel label = new ComponentModel("ui", "label");
        label.assignProperty("property:for", "literal:foo");

        // Characters: hello world!
        label.addContent("hello world!");

        // Characters: foo
        label.addContent("foo");

        // EndElement: </ui:label>
        panel.add(label);

        // StartElement: <ui:input id="literal:foo">
        ComponentModel input = new ComponentModel("ui", "input");
        input.assignProperty("property:id", "literal:foo");

        // EndElement </ui:input>
        panel.add(input);

        // StartElement: <ui:acomponent a="literal:2" b="literal:Foo!" c="prop:othercomponent">
        ComponentModel acomponent = new ComponentModel("ui", "acomponent");
        acomponent.assignProperty("property:a", "literal:2");
        acomponent.assignProperty("property:b", "literal:Foo!");
        acomponent.assignProperty("property:c", "prop:othercomponent");
        // EndElement: </ui:acomponent>

        // EndElement </ui:panel>

        panel.createInstance();
    }
}

class ComponentModel
{
    public ComponentModel() {
    }
}

// TODO Jede Komponente, die @Named hat und Component (wg. ID, Container) implementiert, soll auch über UI Binder
// verwendbar sein -> Im Transformer berücksichtigen

@Named("acomponent")
class AComponent
{
    // TODO vielleicht gleich auf @Property zurückgreifen? -> Ist aber ein semantischer Unterschied.
    // TODO ggf. default binding prefix setzen können? macht das sinn?
    @Binds("a")
    private int a;

    @Binds("b")
    private String b;

    @Binds("c")
    public void setC(Component c) {

    }

    // generated stuff below

    @Inject
    private ConverterService converterService;

    public String getBindableName() {
        return "acomponent";
    }

    public void setBindableValue(String bindableName, Object bindableValue) {
        if ("a".equals(bindableName)) {
            // TODO Kann der ExpressionResolver auch den ConverterService verwenden? Wie wird momentan konvertiert??
            // TODO Kann Rendering wieder ohne Rückgabe von PaintBrush erfolgen und ohne temporäre Streams? Es wird doch
            // sowieso wieder nur noch sequentiell gerendert, oder? Dann könnte einfach der OutputStream an den Context
            // gebunden werden. Die PaintBrush-Klassen können diesen sich dann von dort injecten lassen. Wahrscheinlich
            // scheitert das aber doch dann an Aktionen, die im Render-Zyklus passieren können, von denen dann andere
            // Komponenten ihr Rendering abhängig machen müssen... (z.B. Stylesheets)
            a = converterService.convertValue(bindableValue, int.class);
            return;
        }

        if ("b".equals(bindableName)) {
            b = converterService.convertValue(bindableValue, String.class);
            return;
        }

        if ("c".equals(bindableName)) {
            setC(converterService.convertValue(bindableValue, Component.class));
            return;
        }
    }
}
